/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package modelo;

import java.util.ArrayList;
import javax.swing.JOptionPane;

/**
 *
 *
 * @author andre
 */
public class AnalisadorLexico {

    private int[][] matrizDeTransicaoDeEstados;
    int contadorDeLinha;
    int contadorDeColuna;
    boolean novalinha;
    ArrayList<Token> tabelaDeSimbolos;
    String caracteresConsumidos;
    String constante[] = new String[23];

    public AnalisadorLexico() {
        carregaMatrizDeEstados();
        constante[0] = "programa";
        constante[1] = "variaveis";
        constante[2] = "constantes";
        constante[3] = "registro";
        constante[4] = "tipo";
        constante[5] = "funcao";
        constante[6] = "retorno";
        constante[7] = "vazio";
        constante[8] = "principal";
        constante[9] = "se";
        constante[10] = "entao";
        constante[11] = "senao";
        constante[12] = "enquanto";
        constante[13] = "para";
        constante[14] = "leia";
        constante[15] = "escreva";
        constante[16] = "inteiro ";
        constante[17] = "real ";
        constante[18] = "logico";
        constante[19] = "caractere";
        constante[20] = "cadeia";
        constante[21] = "verdadeiro";
        constante[22] = "falso";
        contadorDeColuna = 0;
        contadorDeLinha = 1;
        novalinha = false;
        tabelaDeSimbolos = new ArrayList<>();
        String constante[] = new String[23];
        caracteresConsumidos = "";
    }

    /**
     * Carrega do arquivo a configuração de transição de estados para a matriz
     * de transição de estados.
     */
    public void carregaMatrizDeEstados() {
    }

    /**
     * Método resposável por realizar a análise léxica do código-fonte.
     *
     * @param codigoFonte
     */
    public void analiseLexica(String codigoFonte) {
        tabelaDeSimbolos.clear();

        System.out.println("\n  Código Fonte: " + codigoFonte + "\n");
        int tabelaDeTransicao[][] = new TabelaTransicao().getMatrix();
        int controleIdentificador = 0;
        int controleComentarioLinha = 0;
        int controleIdFormado = 0;
        int estado_atual = 0;
        int estado_futuro = 0;
        int controladorInt = 0;

        int i = 0;
        while (i < codigoFonte.length()) {

            char simbolo = codigoFonte.charAt(i);
            int ascii_cod = (int) simbolo;
            //int ascii_cod =26;
            switch (ascii_cod) { // switch para tratamento dos simbolos com codigo ascii < 32.
                case 9: {
                    System.out.println("Capturei uma tabulação \t");
                    //tratamento aqui
                    ascii_cod = 129;
                    break;
                }
                case 10: {
                    System.out.println("Capturei um enter \n");
                    //tratamento aqui
                    // exemplo: ascii_cod = 32; (usando 32 só pra teste)

                    ascii_cod = 128;
                    novalinha = true;
                    break;
                }
                case 26: {
                    System.out.println("Capturei um EOF");
                    JOptionPane.showMessageDialog(null, "Fim do Arquivo");
                    int controle;
                    for (controle = 0; controle < tabelaDeSimbolos.size(); controle++) {
                        System.out.println(tabelaDeSimbolos.get(controle));

                    }
                    //aparece um botão de alerta e em seguida mostra a lista de tokens
                    //tratamento aqui
                    // exemplo: ascii_cod = 32;
                    break;
                }
            }

            // identifica qual o próximo estado a partir do estado atual
            estado_futuro = tabelaDeTransicao[estado_atual][ascii_cod - 32];

            switch (estado_futuro) {

                case 2: { // identificador bem formado

                    tabelaDeSimbolos.add(new Token(2, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;

                    break;
                }
                case 3: { // identificador mal formado                   
                    int j = i;
                    j++;
                    if (j >= codigoFonte.length()) {
                        caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                        tabelaDeSimbolos.add(new Token(3, caracteresConsumidos, contadorDeLinha, contadorDeColuna, false));
                        caracteresConsumidos = "";
                        estado_futuro = 0;
                    } else {
                        char simbolo_restante;
                        simbolo_restante = codigoFonte.charAt(j);
                        int aux_asc = (int) codigoFonte.charAt(j);

                        if (aux_asc == 10) {
                            aux_asc = 128;
                        }
                        int posFuturo = tabelaDeTransicao[estado_futuro][aux_asc - 32];

                        if (posFuturo == 0) {

                            caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                            caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo_restante));
                            tabelaDeSimbolos.add(new Token(3, caracteresConsumidos, contadorDeLinha, contadorDeColuna, false));
                            caracteresConsumidos = "";

                            estado_futuro = posFuturo;
                            i = i + 2; // para compensar o consumo do caracter atual + caracter futuro.
                        }
                    }
                    break;
                }
                /*
                 * case 4:{ controladorInt=4; }
                 */
                case 6: { // inteiro bem formado

                    tabelaDeSimbolos.add(new Token(6, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    //estado_futuro=0;
                    //i--;
                    break;
                }
                case 8: { // real mal formado
                    int j = i;
                    j++;
                    char simbolo_restante;
                    simbolo_restante = codigoFonte.charAt(j);
                    int aux_asc = (int) codigoFonte.charAt(j);
                    int posFuturo = tabelaDeTransicao[estado_futuro][aux_asc - 32];

                    if (posFuturo == 0) {
                        System.out.println("Inteiro mal formado: " + caracteresConsumidos);

                        caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                        caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo_restante));
                        tabelaDeSimbolos.add(new Token(9, caracteresConsumidos, contadorDeLinha, contadorDeColuna, false));
                        caracteresConsumidos = "";

                        estado_futuro = posFuturo;
                        i = i + 2; // para compensar o consumo do caracter atual + caracter futuro.
                    }

                    break;

                }
                case 9: { // inteiro mal formado
                    int j = i;
                    j++;
                    char simbolo_restante;
                    simbolo_restante = codigoFonte.charAt(j);
                    int aux_asc = (int) codigoFonte.charAt(j);
                    int posFuturo = tabelaDeTransicao[estado_futuro][aux_asc - 32];

                    if (posFuturo == 0) {


                        caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                        caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo_restante));
                        tabelaDeSimbolos.add(new Token(9, caracteresConsumidos, contadorDeLinha, contadorDeColuna, false));
                        caracteresConsumidos = "";

                        estado_futuro = posFuturo;
                        i = i + 2; // para compensar o consumo do caracter atual + caracter futuro.
                    }

                    break;
                }
                case 13: { // comentário de bloco bem formado
                    caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                    tabelaDeSimbolos.add(new Token(13, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    i++;
                    break;
                }
                case 14: { // operador de divisão

                    tabelaDeSimbolos.add(new Token(14, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    break;
                }
                case 15: { // comentário de linha

                    int j = i;
                    j++;
                    if (j >= codigoFonte.length()) {
                        caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                        tabelaDeSimbolos.add(new Token(15, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                        caracteresConsumidos = "";
                        estado_futuro = 0;
                    } else {
                        char simbolo_restante;
                        simbolo_restante = codigoFonte.charAt(j);
                        int aux_asc = (int) codigoFonte.charAt(j);

                        if (aux_asc == 10) {
                            aux_asc = 128;
                        }
                        int posFuturo = tabelaDeTransicao[estado_futuro][aux_asc - 32];

                        if (posFuturo == 0) {

                            caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                            caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo_restante));
                            tabelaDeSimbolos.add(new Token(15, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                            caracteresConsumidos = "";

                            estado_futuro = posFuturo;
                            i = i + 2; // para compensar o consumo do caracter atual + caracter futuro.
                        }
                    }
                    break;

                }
                case 17: { // real bem formado

                    tabelaDeSimbolos.add(new Token(17, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    break;
                }
                case 19: { // cadeia constante bem formada

                    caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    i++;
                    break;
                }
                case 20: { // cadeia constante mal formada

                    tabelaDeSimbolos.add(new Token(20, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    break;
                }
                case 23: { // caractere constante bem formado
                    caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    i++;
                    break;
                }
                case 24: { // caractere constnte mal formado

                    int j = i;
                    j++;
                    if (j >= codigoFonte.length()) {
                        caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                        tabelaDeSimbolos.add(new Token(15, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                        caracteresConsumidos = "";
                        estado_futuro = 0;
                    } else {
                        char simbolo_restante;
                        simbolo_restante = codigoFonte.charAt(j);
                        int aux_asc = (int) codigoFonte.charAt(j);

                        if (aux_asc == 10) {
                            aux_asc = 128;
                        }
                        int posFuturo = tabelaDeTransicao[estado_futuro][aux_asc - 32];

                        if (posFuturo == 0) {

                            caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                            caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo_restante));
                            tabelaDeSimbolos.add(new Token(24, caracteresConsumidos, contadorDeLinha, contadorDeColuna, false));
                            caracteresConsumidos = "";

                            estado_futuro = posFuturo;
                            i = i + 2; // para compensar o consumo do caracter atual + caracter futuro.
                        }
                    }
                    break;
                }
                case 25: { // delimitado ponto e vigula
                    caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    i++;  // compensa o consumo do caracter do futuro
                    break;
                }
                case 26: { // delimitador virgula

                    caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    i++;
                    break;
                }
                case 27: { // delimitador abre parenteses
                    caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    i++;
                    break;
                }
                case 28: { // delimitador fecha parenteses
                    caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    i++;
                    break;
                }
                case 29: { // delimitador abre chaves
                    caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    i++;
                    break;
                }
                case 30: { // delimitador fecha chaves
                    caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    i++;
                    break;
                }
                case 31: { // delimitador abre colchetes
                    caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    i++;
                    break;
                }
                case 32: { // delimitador fecha colchetes
                    caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    i++;
                    break;
                }
                case 34: { // operador de incremento

                    caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    i++;
                    break;
                }
                case 35: { // operador de soma

                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;

                    break;
                }
                case 37: { // operador de decremento

                    caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    i++;
                    break;
                }
                case 38: { // operador de subtração

                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    break;
                }
                case 39: { // operador de multiplicação

                    caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    i++;
                    break;
                }
                case 41: { // operador de atribuição

                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    break;
                }
                case 42: { // operador de comparação
                    caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    i++;
                    break;
                }
                case 44: { // operador de diferença

                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    break;
                }
                case 45: { // operador mal formado

                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, false));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    break;
                }
                case 47: { // operador maior

                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    break;
                }
                case 48: { // operador maior igual
                    caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    i++;
                    break;
                }
                case 50: { // operador menor igual

                    caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    i++;
                    break;
                }
                case 51: { // operador menor

                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    break;
                }
                case 56: { // operador lógico OU

                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    break;
                }
                case 57: { // operador lógico E

                    tabelaDeSimbolos.add(new Token(estado_futuro, caracteresConsumidos, contadorDeLinha, contadorDeColuna, true));
                    caracteresConsumidos = "";
                    estado_futuro = 0;
                    break;
                }
            }
            estado_atual = estado_futuro;


            if (estado_futuro != 0) { // Se estado_futuro == 0 o caractere atual não é consumido
                i++;
                contadorDeColuna++;
                caracteresConsumidos = caracteresConsumidos.concat(String.valueOf(simbolo));
            }

            if (estado_futuro == 0 && estado_atual == 0) {
                if (ascii_cod == 32) { // Consumo do espaço em branco quando o automato estiver no estado inicial (q0).
                    i++;
                }
            }



            if (novalinha) {
                contadorDeLinha++;
                contadorDeColuna = 0;
                novalinha = false;
            }

        }
        int controle;

        if (i >= codigoFonte.length()) {


            JOptionPane.showMessageDialog(null, "Fim do Arquivo atingido");

            for (controle = 0; controle < tabelaDeSimbolos.size(); controle++) {
                System.out.println("Lexema: " + tabelaDeSimbolos.get(controle).getLexema());
                System.out.println("Token: " + tabelaDeSimbolos.get(controle).getToken());

            }

        }
    }

    /**
     * Metodo que devolve uma string formatada para ser exibida na janela de
     * tokens.
     *
     * @return
     */
    public String getResultado() {

        String resultado = " Resultado da Análise Léxica \n\n";

        for (int i = 0; i < tabelaDeSimbolos.size(); i++) {

            resultado = resultado.concat("Token: " + tabelaDeSimbolos.get(i).getToken() + "\n");
            resultado = resultado.concat("Lexema: " + tabelaDeSimbolos.get(i).getLexema() + "\n");
            resultado = resultado.concat("Bem Formado: " + tabelaDeSimbolos.get(i).isBemFormado() + "\n");
            if (!tabelaDeSimbolos.get(i).isBemFormado()) {
                resultado = resultado.concat("Linha: " + tabelaDeSimbolos.get(i).getLinha() + "\n");
                resultado = resultado.concat("Coluna: " + tabelaDeSimbolos.get(i).getColuna() + "\n");
            }
            resultado = resultado.concat("\n\n");

        }


        return resultado;
    }
}
